#include "io.h"
#include "system.h"
#include "SJA1000_REG.h"
#include "SJA1000_functions.h"
#include "SJA1000.h"

void SJA1000_init()
{
  unsigned int rt;
  unsigned char reg;
  
  /*enter reset mode*/
  do
  {
    IOWR_8DIRECT(SJA1000_BASE,COMM_CTRL,(rt&0xFE)|0x01);
    rt=IORD_8DIRECT(SJA1000_BASE,COMM_CTRL);
  }while((rt & COMM_CTRL_RST) !=COMM_CTRL_RST);
  
  /*clock divider register*/
  reg=(SJA1000_CANMODE<<7) | 
      (SJA1000_CBP<<6) | 
      (SJA1000_RXINTEN<<5) | 
      (SJA1000_CLKOFF<<3) | 
      SJA1000_CD;
  IOWR_8DIRECT(SJA1000_BASE,COMM_CLKDIV,reg);
  
  /*output control register*/
  reg=(SJA1000_OCTP1<<7) | 
      (SJA1000_OCTN1<<6) | 
      (SJA1000_OCPOL1<<5) | 
      (SJA1000_OCTP0<<4) | 
      (SJA1000_OCTN0<<3) | 
      (SJA1000_OCPOL0<<2) | 
      SJA1000_OCMODE;
  IOWR_8DIRECT(SJA1000_BASE,COMM_OUTCTRL,reg);
  
  /*bus timing register*/
  reg=(SJA1000_SJW<<6) | SJA1000_BRP;
  IOWR_8DIRECT(SJA1000_BASE,COMM_BUSTIME0,reg);
  reg=(SJA1000_SAM<<7) | (SJA1000_TSEG2<<4) | SJA1000_TSEG1;
  IOWR_8DIRECT(SJA1000_BASE,COMM_BUSTIME1,reg);
  
  /*acceptance code*/
  IOWR_8DIRECT(SJA1000_BASE,PCAN_ACPCODE,0);
  IOWR_8DIRECT(SJA1000_BASE,PCAN_ACPCODE+1,0);
  IOWR_8DIRECT(SJA1000_BASE,PCAN_ACPCODE+2,0);
  IOWR_8DIRECT(SJA1000_BASE,PCAN_ACPCODE+3,0);
  
  /*acceptance mask*/
  IOWR_8DIRECT(SJA1000_BASE,PCAN_ACPMASK,0xff);
  IOWR_8DIRECT(SJA1000_BASE,PCAN_ACPMASK+1,0xff);
  IOWR_8DIRECT(SJA1000_BASE,PCAN_ACPMASK+2,0xff);
  IOWR_8DIRECT(SJA1000_BASE,PCAN_ACPMASK+3,0xff);
  
  /*interrupt*/
  
  /*enter operation mode*/
  if(SJA1000_CANMODE)   //Peli CAN mode
  {
	  do
	  {
	    IOWR_8DIRECT(SJA1000_BASE,PCAN_MODE,0x00);
      rt=IORD_8DIRECT(SJA1000_BASE,PCAN_MODE);
	  }while((rt & COMM_CTRL_RST) ==COMM_CTRL_RST);
  }
  else                  //Basic CAN mode
  {
	  do
	  {
	    IOWR_8DIRECT(SJA1000_BASE,BCAN_CTRL,0x20);
      rt=IORD_8DIRECT(SJA1000_BASE,BCAN_CTRL);
	  }while((rt & COMM_CTRL_RST) ==COMM_CTRL_RST);
  }
}

void SJA1000_write(CAN_PACKAGE *package)
{
  unsigned char reg;
  int i;
  
  /*wait transmission*/
  do
  {
    reg=IORD_8DIRECT(SJA1000_BASE,PCAN_STATUS);
  }while((reg & PCAN_STATUS_TBS)!=PCAN_STATUS_TBS);
  
  /*write frame information*/
  reg=((package->format & 0x01) << 7) | ((package->RTR & 0x01) << 6) | package->DLC;
  IOWR_8DIRECT(SJA1000_BASE,PCAN_FRAMEINF,reg);
  
  
  if(package->format==0)    //SFF
  {
    /*write ID*/
    reg=(package->ID & 0x1fe00000)>>21;
    IOWR_8DIRECT(SJA1000_BASE,PCAN_ID,reg);
    reg=((package->ID & 0x001c0000)>>13) | ((package->RTR & 0x01)<<4);
    IOWR_8DIRECT(SJA1000_BASE,PCAN_ID+1,reg);
    
    /*write data*/
    for(i=0;i<package->DLC;i++)
    {
      IOWR_8DIRECT(SJA1000_BASE,PCAN_SFFDATA+i,package->data[i]);
    }
  }
  else                      //EFF
  {
    /*write ID*/
    reg=(package->ID & 0x1fe00000)>>21;
    IOWR_8DIRECT(SJA1000_BASE,PCAN_ID,reg);
    reg=(package->ID & 0x001fe000)>>13;
    IOWR_8DIRECT(SJA1000_BASE,PCAN_ID+1,reg);
    reg=(package->ID & 0x00001fe0)>>5;
    IOWR_8DIRECT(SJA1000_BASE,PCAN_ID+2,reg);
    reg=(package->ID & 0x0000001f)<<3;
    IOWR_8DIRECT(SJA1000_BASE,PCAN_ID+3,reg);
    
    /*write data*/
    for(i=0;i<package->DLC;i++)
    {
      IOWR_8DIRECT(SJA1000_BASE,PCAN_EFFDATA+i,package->data[i]);
    }
  }
  IOWR_8DIRECT(SJA1000_BASE,PCAN_CMD,0x01);
}

void SJA1000_read(CAN_PACKAGE *package)
{
  unsigned char reg;
  int i;
  
  /*wait reception*/
  do
  {
    reg=IORD_8DIRECT(SJA1000_BASE,PCAN_STATUS);
  }while((reg & PCAN_STATUS_RBS)!=PCAN_STATUS_RBS);
  
  /*read frame information*/
  reg=IORD_8DIRECT(SJA1000_BASE,PCAN_FRAMEINF);
  package->format=(reg & 0x80) >> 7;
  package->RTR=(reg & 0x40) >> 6;
  package->DLC=reg & 0x0f;
  
  if(package->format==0)    //SFF
  {
    /*read ID*/
    reg=IORD_8DIRECT(SJA1000_BASE,PCAN_ID);
    package->ID=reg << 21;
    reg=IORD_8DIRECT(SJA1000_BASE,PCAN_ID);
    package->ID=(reg & 0xe0) << 13;
    
    /*read data*/
    for(i=0;i<package->DLC;i++)
    {
      package->data[i]=IORD_8DIRECT(SJA1000_BASE,PCAN_SFFDATA+i);
    }
  }
  else                      //EFF
  {
    /*read ID*/
    reg=IORD_8DIRECT(SJA1000_BASE,PCAN_ID);
    package->ID=reg << 21;
    reg=IORD_8DIRECT(SJA1000_BASE,PCAN_ID+1);
    package->ID=package->ID | (reg << 13);
    reg=IORD_8DIRECT(SJA1000_BASE,PCAN_ID+2);
    package->ID=package->ID | (reg<<5);
    reg=IORD_8DIRECT(SJA1000_BASE,PCAN_ID+3);
    package->ID=package->ID | ((reg & 0xf8)>>3);
    
    
    /*read data*/
    for(i=0;i<package->DLC;i++)
    {
      package->data[i]=IORD_8DIRECT(SJA1000_BASE,PCAN_EFFDATA+i);
    }
  }
  IOWR_8DIRECT(SJA1000_BASE,PCAN_CMD,0x04);
}